home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / p4 / p4-1_2c.lha / p4-1.2c / servers / serv_p4.c < prev    next >
C/C++ Source or Header  |  1993-05-24  |  17KB  |  865 lines

  1. #include "p4.h"
  2. #include "p4_sys.h"
  3.  
  4. /****
  5. #include <stdio.h>
  6. #include <ctype.h>
  7. #include <pwd.h>
  8. #include <errno.h>
  9. #include <signal.h>
  10. #include <netdb.h>
  11. #include <sys/socket.h>
  12. #include <sys/types.h>
  13. #include <netinet/in.h>
  14. #include <arpa/inet.h>
  15. #include <time.h>
  16. ****/
  17.  
  18. #include <sys/stat.h>
  19. #include <sys/file.h>
  20. #include <sys/ioctl.h>
  21.  
  22. extern char *inet_ntoa();    /* from <arpa/inet.h> */
  23.  
  24. #ifdef P4BSD
  25. #include <strings.h>
  26. #endif
  27.  
  28. #ifdef P4SYSV
  29. #include <string.h>
  30. #endif
  31.  
  32. #if defined(SYMMETRY)
  33. #define NEED_GETOPT
  34. #endif
  35.  
  36. #ifdef NEED_GETOPT
  37.  
  38. /* This is from the released BSD sources lib/libc/getopt.c */
  39.  
  40. /*
  41.  * get option letter from argument vector
  42.  */
  43. int    opterr = 1,        /* if error message should be printed */
  44.     optind = 1,        /* index into parent argv vector */
  45.     optopt;            /* character checked for validity */
  46. char    *optarg;        /* argument associated with option */
  47.  
  48. #else
  49.  
  50. extern char *optarg;
  51.  
  52. #endif
  53.  
  54. #define MAXARGS 256
  55.  
  56. #ifndef LOGFILE
  57. #define LOGFILE "/usr/adm/serv_p4.log"
  58. #endif
  59.  
  60. #define notice2(a,b) {sprintf(tmpbuf, a, b); notice(tmpbuf);}
  61. #define notice3(a,b,c) {sprintf(tmpbuf, a, b,c); notice(tmpbuf);}
  62. #define failure2(a,b) {sprintf(tmpbuf, a, b); failure(tmpbuf);}
  63.  
  64. extern char *crypt();
  65.  
  66. extern char *sys_errlist[];
  67. extern int errno;
  68.  
  69. char tmpbuf[1024];
  70. char *fromhost;
  71.  
  72. char logfile[1024];
  73. FILE *logfile_fp;
  74.  
  75. #define DEFAULT_PORT 753
  76.  
  77. int daemon_mode;
  78. int daemon_port;
  79. int debug;
  80.  
  81. char *this_username;
  82. int this_uid;
  83.  
  84. void doit();
  85. void execute();
  86. int getline();
  87. void failure();
  88. void notice();
  89. int net_accept();
  90. void net_setup_listener();
  91. void net_setup_anon_listener();
  92. void error_check();
  93. char *timestamp();
  94.  
  95. char *save_string();
  96. static int connect_to_listener();
  97.  
  98. void reaper()
  99. {
  100.     int i;
  101.     wait(&i);
  102. }
  103.  
  104. main(argc, argv)
  105. int argc;
  106. char **argv;
  107. {
  108.     int c;
  109.     struct sockaddr_in name;
  110.     int namelen;
  111.  
  112.     if (getuid() == 0)
  113.     {
  114.     strcpy(logfile, LOGFILE);
  115.     daemon_port = DEFAULT_PORT;
  116.     }
  117.     else
  118.     {
  119.     sprintf(logfile, "P4Server.Log.%d", getpid());
  120.     daemon_port = 0;
  121.     debug = 1;
  122.     }
  123.  
  124.     namelen = sizeof(name);
  125.     if (getpeername(0, (struct sockaddr *) &name, &namelen) < 0)
  126.     daemon_mode = 1;
  127.     else
  128.     daemon_mode = 0;
  129.     
  130.     while ((c = getopt(argc, argv, "Ddp:l:")) != EOF)
  131.     {
  132.     switch (c)
  133.     {
  134.     case 'D':
  135.         debug++;
  136.         break;
  137.         
  138.     case 'd':
  139.         daemon_mode++;
  140.         break;
  141.  
  142.     case 'p':
  143.         daemon_port = atoi(optarg);
  144.         break;
  145.  
  146.     case 'l':
  147.         strcpy(logfile, optarg);
  148.         break;
  149.  
  150.     case '?':
  151.     default:
  152.         fprintf(stderr, "Usage: %s [-d] [-D] [-p port] [-l logfile]\n",argv[0]);
  153.         exit(1);
  154.     }
  155.     }
  156.  
  157.     if ((logfile_fp = fopen(logfile, "a")) == NULL)
  158.     {
  159.     if (getuid() != 0)
  160.     {
  161.         printf("Cannot open logfile, disabling logging\n");
  162.         logfile_fp = fopen("/dev/null", "w");
  163.     }
  164.     else
  165.     {
  166.         fprintf(stderr, "Cannot open logfile %s: %s\n",
  167.             logfile, sys_errlist[errno]);
  168.         exit(1);
  169.     }
  170.     }
  171.     else
  172.     printf("Logging to %s\n", logfile);
  173.  
  174.     setbuf(logfile_fp, NULL);
  175.  
  176.     fprintf(logfile_fp, "%s pid=%d starting at %s",
  177.         argv[0], getpid(), timestamp());
  178.  
  179.     if (daemon_mode)
  180.     {
  181.     int port, lfd, fd, pid;
  182.  
  183.     signal(SIGCHLD, reaper);
  184.  
  185.     if (daemon_port == 0)
  186.     {
  187.         net_setup_anon_listener(2, &daemon_port, &lfd);
  188.     }
  189.     else
  190.     {
  191.         net_setup_listener(2, daemon_port, &lfd);
  192.     }
  193.  
  194.     if (debug || daemon_port != DEFAULT_PORT)
  195.         printf("Listening on %d\n", daemon_port);
  196.         
  197.     if (!debug)
  198.     {
  199.         if (fork())
  200.         exit(0);
  201.  
  202.         for (fd = 0; fd < 10; fd++)
  203.         if (fd != lfd && fd != fileno(logfile_fp))
  204.             close(fd);
  205.         
  206. #ifdef P4SYSV
  207.         fd = open ("/dev/console", O_RDWR);
  208.         if (fd < 0)
  209.         fd = open ("/dev/tty", O_RDWR);
  210.         if (fd < 0)
  211.         fd = open ("/dev/null", O_RDWR);
  212. #    if defined(CRAY)
  213.         (void) dup2(0, 1);
  214.         (void) dup2(0, 2);
  215. #    else
  216.         (void) dup2(STDIN_FILENO, STDOUT_FILENO);
  217.         (void) dup2(STDIN_FILENO, STDERR_FILENO);
  218. #    endif
  219.         (void) setpgrp();
  220. #else
  221.         (void) open("/", 0);
  222.         (void) dup2(0, 1);
  223.         (void) dup2(0, 2);
  224.         fd = open("/dev/tty", O_RDWR);
  225.         if (fd >= 0) {
  226.         ioctl(fd, TIOCNOTTY, 0);
  227.         (void) close(fd);
  228.         }
  229. #endif
  230.     }
  231.  
  232.     while (1)
  233.     {
  234.         fd = net_accept(lfd);
  235.  
  236.         pid = fork();
  237.  
  238.         if (pid < 0)
  239.         {
  240.         fprintf(logfile_fp, "Fork failed: %s\n",
  241.             sys_errlist[errno]);
  242.         exit(pid);
  243.         }
  244.         if (pid == 0)
  245.         {
  246. #if defined(HP)
  247.         (void) setpgrp();
  248. #else
  249.         int ttyfd = open("/dev/tty",O_RDWR);
  250.         if (ttyfd >= 0)
  251.         {
  252. #    if !defined(CRAY)
  253.             ioctl(ttyfd, TIOCNOTTY, 0);
  254. #    endif
  255.             close(ttyfd);
  256.         }
  257. #endif
  258.         close(0);
  259.         close(1);
  260.         close(2);
  261.         close(lfd);
  262.         
  263.         dup2(fd, 0);
  264.         dup2(fd, 1);
  265.         dup2(fileno(logfile_fp), 2);
  266.  
  267.         doit(0);
  268.         exit(0);
  269.         }
  270.         close(fd);
  271.     }
  272.     }
  273.     else
  274.     {
  275.     doit(0);
  276.     }
  277.     
  278. }
  279.  
  280. void doit(fd)
  281. int fd;
  282. {
  283.     struct sockaddr_in name;
  284.     int namelen;
  285.     struct hostent *hp;
  286.  
  287.     struct passwd *pw;
  288.     char client_user[80], server_user[80];
  289.     char pgm[1024], pgm_args[1024];
  290.     char *user_home;
  291.     int superuser;
  292.     int valid;
  293.     FILE *fp;
  294.     int stdout_port;
  295.     char stdout_port_str[16];
  296.  
  297.     char filename[1024], progline[1024];
  298.     struct stat statbuf, statbuf_pgm, statbuf_apps_entry;
  299.  
  300.     this_uid = getuid();
  301.     pw = getpwuid(this_uid);
  302.     if (pw == NULL)
  303.     {
  304.     fprintf(logfile_fp, "Cannot get pw entry for user %d\n", this_uid);
  305.     exit(1);
  306.     }
  307.     this_username = save_string(pw->pw_name);
  308.  
  309.     if (this_uid != 0)
  310.     fprintf(logfile_fp, "WARNING: Not run as root\n");
  311.  
  312.     setbuf(stdout, NULL);
  313.  
  314.     fprintf(logfile_fp, "Got connection at %s", timestamp());
  315.  
  316.     namelen = sizeof(name);
  317.  
  318.     if (getpeername(fd, (struct sockaddr *) &name, &namelen) != 0)
  319.     {
  320.     fprintf(logfile_fp, "getpeername failed: %s\n",
  321.         sys_errlist[errno]);
  322.     exit(1);
  323.     }
  324.  
  325.     fromhost = inet_ntoa(name.sin_addr);
  326.     
  327.     hp = gethostbyaddr((char *) &name.sin_addr,
  328.                sizeof(name.sin_addr),
  329.                (int) name.sin_family);
  330.     if (hp == NULL)
  331.     failure2("Cannot get remote address for %s", fromhost);
  332.  
  333.     fromhost = hp->h_name;
  334.  
  335.     if (!getline(client_user, sizeof(client_user)))
  336.     failure("No client user");
  337.  
  338.     if (!getline(server_user, sizeof(server_user)))
  339.     failure("No server user");
  340.  
  341.     pw = getpwnam(server_user);
  342.     if (pw == NULL)
  343.     failure2("No such user: %s\n", server_user);
  344.  
  345.     if (this_uid != 0 && this_uid != pw->pw_uid)
  346.     failure2("Server is not running as root. Only %s can start processes\n",
  347.          this_username);
  348.  
  349.     user_home = pw->pw_dir;
  350.     superuser = (pw->pw_uid == 0);
  351.  
  352.     valid = ruserok(fromhost, superuser, client_user, server_user);
  353.  
  354.     if (valid != 0)
  355.     {
  356.     char user_pw[80];
  357.     char *xpw;
  358.     
  359.     printf("Password\n");
  360.     if (!getline(user_pw, sizeof(user_pw)))
  361.         failure("No server user");
  362.  
  363.     xpw = crypt(user_pw, pw->pw_passwd);
  364.     if (strcmp(pw->pw_passwd, xpw) != 0)
  365.         failure("Invalid password");
  366.  
  367.     printf("Proceed\n");
  368.     }
  369.     else
  370.     printf("Proceed\n");
  371.  
  372.     sprintf(tmpbuf, "authenticated client_id=%s server_id=%s\n",
  373.         client_user, server_user);
  374.     notice(tmpbuf);
  375.  
  376.     if (!getline(pgm, sizeof(pgm)))
  377.     failure("No pgm");
  378.  
  379.     if (!getline(pgm_args, sizeof(pgm_args)))
  380.     failure("No pgm args");
  381.  
  382.     notice2("got args %s", pgm_args);
  383.  
  384.     if (pgm[0] != '/')
  385.     failure2("%s is not a full pathname", pgm);
  386.  
  387.     if (this_uid == 0)
  388.     {
  389. #if defined(HP)
  390.     if (setresuid(-1, pw->pw_uid, -1) != 0)
  391.         failure2("setresuid failed: %s", sys_errlist[errno]);
  392. #else
  393.     if (seteuid(pw->pw_uid) != 0)
  394.         failure2("seteuid failed: %s", sys_errlist[errno]);
  395. #endif
  396.     }
  397.     
  398. #define P4_APP_TEST
  399. #ifdef P4_APP_TEST
  400.     sprintf(filename, "%s/.p4apps", user_home);
  401.     valid = 0;
  402.     
  403.     if ((fp = fopen(filename,"r")) != NULL)
  404.     {
  405.     char *s1, *s2;
  406.     
  407.     if (fstat(fileno(fp), &statbuf) != 0)
  408.         failure2("cannot stat %s", filename);
  409.     
  410.     if (statbuf.st_mode & 077)
  411.         failure(".p4apps readable by others");
  412.     
  413.     while (fgets(progline, sizeof(progline), fp) != NULL)
  414.     {
  415.         s1 = progline;
  416.         while (*s1 && isspace(*s1))
  417.         s1++;
  418.         if (*s1 == '\0' || *s1 == '#')
  419.         continue;
  420.         
  421.         s2 = s1;
  422.         while (*s2 && !isspace(*s2))
  423.         s2++;
  424.         *s2 = 0;
  425.         if (strcmp(pgm, s1) == 0)
  426.         {
  427.         valid = 1;
  428.         break;
  429.         }
  430.         else
  431.         {
  432.         if (stat(pgm, &statbuf_pgm) != 0)
  433.             continue;
  434.         if (stat(s1, &statbuf_apps_entry) != 0)
  435.             continue;
  436.         if (statbuf_pgm.st_ino == statbuf_apps_entry.st_ino)
  437.             valid = 1;
  438.         }
  439.     }
  440.     fclose(fp);
  441.     }
  442.  
  443.     if (!valid)
  444.     failure2("Invalid program %s", pgm);
  445.     
  446.     if (stat(pgm, &statbuf) != 0)
  447.     failure2("Cannot stat %s", pgm);
  448.  
  449.     if (!(statbuf.st_mode & 0111))
  450.     failure2("Cannot execute %s", pgm);
  451. #endif
  452.  
  453.     /*********/
  454.     if (!getline(stdout_port_str, sizeof(stdout_port_str)))
  455.     failure("No stdout");
  456.     else
  457.     stdout_port = atoi(stdout_port_str);
  458.  
  459.     notice2("got stdout_port %d", stdout_port);
  460.     /*********/
  461.  
  462.     notice3("executing %s %s", pgm, pgm_args);
  463.  
  464.     execute(pgm, pgm_args, pw->pw_uid, stdout_port, hp);
  465.         
  466. }
  467.  
  468. void execute(pgm, pgm_args, uid, stdout_port, hp)
  469. char *pgm, *pgm_args;
  470. int uid, stdout_port;
  471. struct hostent *hp;
  472. {
  473.     int p[2];
  474.     int rd, wr;
  475.     int pid, n;
  476.     char *args[MAXARGS];
  477.     int nargs;
  478.     char *s, *end;
  479.     int i;
  480.     char buf[1024];
  481.     int stdout_fd;
  482.     char tempbuf[100];
  483.  
  484.     s = pgm_args;
  485.     while (*s && isspace(*s))
  486.     s++;
  487.  
  488.     args[0] = pgm;
  489.  
  490.     nargs = 1;
  491.     while (*s)
  492.     {
  493.     args[nargs] = s;
  494.  
  495.     while (*s && !isspace(*s))
  496.         s++;
  497.  
  498.     end = s;
  499.  
  500.     while (*s && isspace(*s))
  501.         s++;
  502.  
  503.     *end = 0;
  504.     nargs++;
  505.     if (nargs + 1>= MAXARGS)
  506.         failure("Too many arguments to pgm");
  507.     }
  508.  
  509.     args[nargs] = NULL;
  510.  
  511.     if (pipe(p) != 0)
  512.     failure2("Cannot create pipe: %s", sys_errlist[errno]);
  513.  
  514.     rd = p[0];
  515.     wr = p[1];
  516.  
  517.     if (fcntl(wr, F_SETFD, 1) != 0)
  518.     failure2("fcntl F_SETFD failed: %s", sys_errlist[errno]);
  519.  
  520.     if (this_uid == 0)
  521.     {
  522. #if defined(HP)
  523.     if (setresuid(uid, uid, -1) != 0)
  524.         failure2("cannot setresuid: %s", sys_errlist[errno]);
  525. #else
  526.     if (seteuid(0) != 0)
  527.         failure2("cannot seteuid: %s", sys_errlist[errno]);
  528.     
  529.     if (setreuid(uid, uid) != 0)
  530.         failure2("cannot setreuid: %s", sys_errlist[errno]);
  531. #endif
  532.     }
  533.     
  534.     pid = fork();
  535.     if (pid < 0)
  536.     failure2("fork failed: %s", sys_errlist[errno]);
  537.  
  538.     if (pid == 0)
  539.     {
  540.     close(rd);
  541.  
  542.     close(0);
  543.     open("/dev/null", O_RDONLY);
  544.  
  545.     stdout_fd = connect_to_listener(hp,stdout_port);
  546.     notice2("stdout_fd=%d", stdout_fd);
  547.     close(1);
  548.     dup(stdout_fd);
  549.     /* open("/dev/null", O_WRONLY); */
  550.  
  551.     close(2);
  552.     open("/dev/null", O_WRONLY);
  553.  
  554.     /*****
  555.     strcpy(tempbuf,"writing this to stdout_fd");
  556.     write(stdout_fd,tempbuf,strlen(tempbuf)+1);
  557.     strcpy(tempbuf,"writing this to real stdout");
  558.     write(stdout,tempbuf,strlen(tempbuf)+1);
  559.     *****/
  560.  
  561.     if (execv(pgm, args) != 0)
  562.     {
  563.         sprintf(tmpbuf, "Exec failed: %s\n", sys_errlist[errno]);
  564.         write(wr, tmpbuf, strlen(tmpbuf));
  565.         exit(0);
  566.     }
  567.     }
  568.  
  569.     close(wr);
  570.  
  571.     if ((n = read(rd, buf, sizeof(buf))) > 0)
  572.     {
  573.     buf[n] = 0;
  574.     s = index(buf, '\n');
  575.     if (s)
  576.         *s = 0;
  577.     
  578.     failure2("child failed: %s", buf);
  579.     }
  580.     printf("Success: Child %d started\n", pid);
  581.     notice2("Child %d started", pid);
  582. }
  583.  
  584. int getline(str, len)
  585. char *str;
  586. int len;
  587. {
  588.     char *s;
  589.     
  590.     if (fgets(str,  len, stdin) == NULL)
  591.     return 0;
  592.  
  593.     if ((s = index(str, '\n')) != NULL)
  594.     *s = 0;
  595.     if ((s = index(str, '\r')) != NULL)
  596.     *s = 0;
  597.     return 1;
  598. }
  599.     
  600.  
  601. void failure(s)
  602. char *s;
  603. {
  604.     printf("Failure <%s>: %s\n", fromhost, s);
  605.     fprintf(logfile_fp, "Failure <%s>: %s\n", fromhost, s);
  606.     fflush(logfile_fp);
  607.     exit(1);
  608. }
  609.  
  610. void notice(s)
  611. char *s;
  612. {
  613.     fprintf(logfile_fp, "Notice <%s>: %s\n", fromhost, s);
  614.     fflush(logfile_fp);
  615. }
  616.  
  617.  
  618. /*
  619.   Accept a connection on socket skt and return fd of new connection.
  620.  */
  621. int net_accept(skt)
  622. int skt;
  623. {
  624. struct sockaddr_in from;
  625. int fromlen;
  626. int skt2;
  627. int gotit;
  628.  
  629.     fromlen = sizeof(from);
  630.     gotit = 0;
  631.     while (!gotit)
  632.     {
  633.     skt2 = accept(skt, (struct sockaddr *) &from, &fromlen);
  634.     if (skt2 == -1)
  635.     {
  636.         if (errno == EINTR)
  637.         continue;
  638.         else
  639.         error_check(skt2, "net_accept accept");
  640.     }
  641.     else
  642.         gotit = 1;
  643.     }
  644.  
  645.     return(skt2);
  646. }
  647.  
  648. void net_setup_listener(backlog, port, skt)
  649. int backlog, port, *skt;
  650. {
  651. int sinlen;
  652. struct sockaddr_in sin, from;
  653.  
  654.     *skt = socket(AF_INET, SOCK_STREAM, 0);
  655.  
  656.     error_check(*skt,"net_setup_anon_listener socket");
  657.  
  658.     sin.sin_family = AF_INET;
  659.     sin.sin_addr.s_addr = INADDR_ANY;
  660.     sin.sin_port = htons(port);
  661.  
  662.     sinlen = sizeof(sin);
  663.  
  664.     error_check(bind(*skt,(struct sockaddr *) &sin,sizeof(sin)),
  665.            "net_setup_listener bind");
  666.  
  667.  
  668.     error_check(listen(*skt, backlog), "net_setup_listener listen");
  669. }
  670.  
  671. void net_setup_anon_listener(backlog, port, skt)
  672. int backlog, *port, *skt;
  673. {
  674. int sinlen;
  675. struct sockaddr_in sin, from;
  676.  
  677.     *skt = socket(AF_INET, SOCK_STREAM, 0);
  678.  
  679.     error_check(*skt,"net_setup_anon_listener socket");
  680.  
  681.     sin.sin_family = AF_INET;
  682.     sin.sin_addr.s_addr = INADDR_ANY;
  683.     sin.sin_port = htons(0);
  684.  
  685.     sinlen = sizeof(sin);
  686.  
  687.     error_check(bind(*skt,(struct sockaddr *) &sin,sizeof(sin)),
  688.            "net_setup_anon_listener bind");
  689.  
  690.  
  691.     error_check(listen(*skt, backlog), "net_setup_anon_listener listen");
  692.  
  693.     getsockname(*skt, (struct sockaddr *) &sin, &sinlen);
  694.     *port = ntohs(sin.sin_port);
  695. }
  696.  
  697. void error_check(val, str)
  698. int val;
  699. char *str;
  700. {
  701.     if (val < 0)
  702.     {
  703.     fprintf(logfile_fp, "%s: %s\n",
  704.         str,
  705.         sys_errlist[errno]);
  706.     exit(1);
  707.     }
  708. }
  709.  
  710.  
  711. char *timestamp()
  712. {
  713.     long clock;
  714.     struct tm *tmp;
  715.  
  716.     clock = time(0L);
  717.     tmp = localtime(&clock);
  718.     return asctime(tmp);
  719. }
  720.  
  721. char *save_string(s)
  722. char *s;
  723. {
  724.     char *rc = (char *) malloc(strlen(s) + 1);
  725.     strcpy(rc, s);
  726.     return rc;
  727. }
  728.  
  729. #ifdef NEED_GETOPT
  730. /* This is from the released BSD sources lib/libc/getopt.c */
  731. /*
  732.  * Copyright (c) 1987 Regents of the University of California.
  733.  * All rights reserved.
  734.  *
  735.  * Redistribution and use in source and binary forms, with or without
  736.  * modification, are permitted provided that the following conditions
  737.  * are met:
  738.  * 1. Redistributions of source code must retain the above copyright
  739.  *    notice, this list of conditions and the following disclaimer.
  740.  * 2. Redistributions in binary form must reproduce the above copyright
  741.  *    notice, this list of conditions and the following disclaimer in the
  742.  *    documentation and/or other materials provided with the distribution.
  743.  * 3. All advertising materials mentioning features or use of this software
  744.  *    must display the following acknowledgement:
  745.  *    This product includes software developed by the University of
  746.  *    California, Berkeley and its contributors.
  747.  * 4. Neither the name of the University nor the names of its contributors
  748.  *    may be used to endorse or promote products derived from this software
  749.  *    without specific prior written permission.
  750.  *
  751.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  752.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  753.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  754.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  755.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  756.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  757.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  758.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  759.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  760.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  761.  * SUCH DAMAGE.
  762.  */
  763.  
  764. #define    BADCH    (int)'?'
  765. #define    EMSG    ""
  766.  
  767. int
  768. getopt(nargc, nargv, ostr)
  769.     int nargc;
  770.     char **nargv;
  771.     char *ostr;
  772. {
  773.     static char *place = EMSG;        /* option letter processing */
  774.     register char *oli;            /* option letter list index */
  775.     char *p;
  776.  
  777.     if (!*place) {                /* update scanning pointer */
  778.         if (optind >= nargc || *(place = nargv[optind]) != '-') {
  779.             place = EMSG;
  780.             return(EOF);
  781.         }
  782.         if (place[1] && *++place == '-') {    /* found "--" */
  783.             ++optind;
  784.             place = EMSG;
  785.             return(EOF);
  786.         }
  787.     }                    /* option letter okay? */
  788.     if ((optopt = (int)*place++) == (int)':' ||
  789.         !(oli = index(ostr, optopt))) {
  790.         /*
  791.          * if the user didn't specify '-' as an option,
  792.          * assume it means EOF.
  793.          */
  794.         if (optopt == (int)'-')
  795.             return(EOF);
  796.         if (!*place)
  797.             ++optind;
  798.         if (opterr) {
  799.             if (!(p = rindex(*nargv, '/')))
  800.                 p = *nargv;
  801.             else
  802.                 ++p;
  803.             (void)fprintf(stderr, "%s: illegal option -- %c\n",
  804.                 p, optopt);
  805.         }
  806.         return(BADCH);
  807.     }
  808.     if (*++oli != ':') {            /* don't need argument */
  809.         optarg = NULL;
  810.         if (!*place)
  811.             ++optind;
  812.     }
  813.     else {                    /* need an argument */
  814.         if (*place)            /* no white space */
  815.             optarg = place;
  816.         else if (nargc <= ++optind) {    /* no arg */
  817.             place = EMSG;
  818.             if (!(p = rindex(*nargv, '/')))
  819.                 p = *nargv;
  820.             else
  821.                 ++p;
  822.             if (opterr)
  823.                 (void)fprintf(stderr,
  824.                     "%s: option requires an argument -- %c\n",
  825.                     p, optopt);
  826.             return(BADCH);
  827.         }
  828.          else                /* white space */
  829.             optarg = nargv[optind];
  830.         place = EMSG;
  831.         ++optind;
  832.     }
  833.     return(optopt);                /* dump back option letter */
  834. }
  835.  
  836. #endif
  837.  
  838. static int connect_to_listener(hp,stdout_port)
  839. struct hostent *hp;
  840. int stdout_port;
  841. {
  842.     int conn;
  843.     int rc;
  844.     struct sockaddr_in addr;
  845.  
  846.     conn = socket(AF_INET, SOCK_STREAM, 0);
  847.     if (conn < 0)
  848.     {
  849.     failure("connect_to_listener: socket failed");
  850.     }
  851.  
  852.     addr.sin_family = hp->h_addrtype;
  853.     addr.sin_port = htons(stdout_port);
  854.     bcopy(hp->h_addr, &addr.sin_addr, hp->h_length);
  855.  
  856.     rc = connect(conn, (struct sockaddr *) & addr, sizeof(addr));
  857.     if (rc < 0)
  858.     {
  859.     failure("connect_to_listener: connect failed");
  860.     }
  861.  
  862.     return conn;
  863. }
  864.  
  865.